package org.zoomdev.zoom.aop.utils;

import org.objectweb.asm.*;
import org.objectweb.asm.commons.GeneratorAdapter;
import org.zoomdev.zoom.common.caster.Caster;
import org.zoomdev.zoom.common.utils.Classes;

import java.lang.reflect.Constructor;
import java.lang.reflect.Executable;
import java.lang.reflect.Method;

import static org.objectweb.asm.Opcodes.*;
import static org.objectweb.asm.Type.*;

public final class AsmUtils {
    public static final int VERSION = Classes.isJava8() ? V1_8 : V21;

    private AsmUtils() {

    }

    public static String[] getExceptionTypes(Executable method) {
        Class<?>[] exceptions = method.getExceptionTypes();
        String[] exceptionInternalNames = new String[exceptions.length];
        for (int i = 0; i < exceptions.length; i++) {
            exceptionInternalNames[i] = Type.getInternalName(exceptions[i]);
        }
        return exceptionInternalNames;
    }

    /**
     * 默认无参数
     *
     * @param cw
     */
    public static void generateDefaultConstructor(ClassWriter cw) {
        generateConstructor(cw, "java/lang/Object");
    }

    /**
     * 无参数
     *
     * @param cw
     */
    public static void generateConstructor(ClassWriter cw, String superName) {
        MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
        mv.visitCode();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESPECIAL, superName, "<init>", "()V", false);
        mv.visitInsn(RETURN);
        mv.visitMaxs(1, 1);
        mv.visitEnd();
    }

    /**
     * 具体类型返回Object
     */
    public static void generateReturnObject(GeneratorAdapter mg, Type returnType) {
        if (returnType == Type.VOID_TYPE) {
            mg.visitInsn(ACONST_NULL);
            mg.visitInsn(Opcodes.RETURN);
        } else if (returnType.getSort() == Type.OBJECT) {
            // 定义标签
            mg.checkCast(returnType);
            mg.visitInsn(ARETURN);
        } else {
            mg.unbox(returnType);
            mg.returnValue();
        }
    }


    public static void unboxIfPrimitive(MethodVisitor mv, Class<?> returnType) {
        if (returnType.isPrimitive()) {
            String methodName = returnType.getName() + "Value";
            mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(Caster.getWrapClass(returnType)));
            mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL,
                    Type.getInternalName(Caster.getWrapClass(returnType)),
                    methodName,
                    "()" + Type.getDescriptor(returnType),
                    false);
        } else {
            mv.visitTypeInsn(Opcodes.CHECKCAST, Type.getInternalName(returnType));
        }
    }

    public static void boxIfPrimitive(MethodVisitor mv, Class<?> type) {
        if (type.isPrimitive()) {
            Type wrapperType = Type.getType(Caster.getWrapClass(type));
            mv.visitMethodInsn(Opcodes.INVOKESTATIC,
                    wrapperType.getInternalName(),
                    "valueOf",
                    "(" + Type.getDescriptor(type) + ")" + wrapperType.getDescriptor(),
                    false);
        }
    }


    public static String makeExternalName(String str) {
        return str.replace('.', '/');
    }


    public static void generateConstructor(ClassWriter cw, String className, Constructor<?> constructor) {
        // 获取参数类型描述符（如 (II)V）
        String descriptor = Type.getConstructorDescriptor(constructor);

        // 创建 MethodVisitor
        MethodVisitor mv = cw.visitMethod(
                Opcodes.ACC_PUBLIC,
                "<init>",
                descriptor,
                null,
                null
        );

        // 加载 this 引用
        mv.visitVarInsn(Opcodes.ALOAD, 0);

        // 加载所有参数到栈上
        Class<?>[] paramTypes = constructor.getParameterTypes();
        for (int i = 0; i < paramTypes.length; i++) {
            int opcode = getLoadOpcode(paramTypes[i]); // 根据类型选择 ILOAD/ALOAD 等
            mv.visitVarInsn(opcode, i + 1); // 参数从索引 1 开始
        }

        // 调用父类构造器
        mv.visitMethodInsn(
                Opcodes.INVOKESPECIAL,
                className,
                "<init>",
                descriptor,
                false
        );

        // 返回指令
        mv.visitInsn(Opcodes.RETURN);

        // 自动计算最大栈和局部变量表
        mv.visitMaxs(0, 0); // 由 COMPUTE_MAXS 自动计算
        mv.visitEnd();
    }

    private static int getLoadOpcode(Class<?> type) {
        if (type == int.class || type == byte.class || type == short.class) {
            return Opcodes.ILOAD;
        } else if (type == long.class) {
            return Opcodes.LLOAD;
        } else if (type == float.class) {
            return Opcodes.FLOAD;
        } else if (type == double.class) {
            return Opcodes.DLOAD;
        } else {
            return Opcodes.ALOAD; // 对象类型
        }
    }

    public static String restoreClassName(String type) {
        return type.replace('/', '.');
    }

    public static void addField(ClassVisitor cv,int access, String name, Class<?> type){
        addField(cv,access,name,Type.getDescriptor(type));
    }

    public static void addField(ClassVisitor cv,int access, String name, String descriptor) {
        cv.visitField(access, name,descriptor, null, null).visitEnd();
    }

    public static String getPrimitiveWrapperType(Class<?> primitiveType) {
        if (primitiveType == int.class) return "Integer";
        if (primitiveType == long.class) return "Long";
        if (primitiveType == float.class) return "Float";
        if (primitiveType == double.class) return "Double";
        if (primitiveType == boolean.class) return "Boolean";
        if (primitiveType == byte.class) return "Byte";
        if (primitiveType == short.class) return "Short";
        if (primitiveType == char.class) return "Character";
        throw new IllegalArgumentException("Not a primitive type: " + primitiveType);
    }
}
